# -*- coding: utf-8 -*-

# manpage/build_manpages.py
# Part of ‘manpage’, a Python library for making Unix manual documents.
#
# Copyright © 2016 Ben Finney <ben+python@benfinney.id.au>
#
# This is free software: see the grant of license at end of this file.

""" Distutils integration to build Unix “man page” documents. """

import os
import os.path
import distutils.core
from distutils.errors import DistutilsOptionError

from . import document
from . import argparse_help


class BuildManPages(distutils.core.Command, object):
    """ Generate Unix “man page” documents for this distribution. """

    description = (
            "Generate Unix “man page” documents for this distribution.")

    user_options = [
            ('output-dir=', 'O', (
                "Filesystem path to output directory."
                " (example: 'doc/')"
                " (default: '.')")),
            ]

    def initialize_options(self):
        """ Set defaults for options this command supports. """
        self.output_dir = os.path.curdir

    def finalize_options(self):
        """ Set final values for options this command supports. """
        self.ensure_dirname('output_dir')

        for (output_name, maker) in self.manpage_makers.items():
            maker.output_path = os.path.join(self.output_dir, output_name)

    def build_manpage(self, maker):
        """ Build a manual page document to its output file.

            :param maker: The `document.ManPageMaker` instance to
                create the document.
            :return: None.

            """
        self.announce(
                "Building manual page document ‘{name}({section})’".format(
                    name=maker.metadata.name,
                    section=maker.metadata.section))

        builder = DocumentBuilder(maker, self.distribution)
        manpage = builder.build()

        return manpage

    def write_manpage(self, manpage, outfile_path):
        """ Write the manual page document to the output file.

            :param manpage: The document to write to the output file.
            :param outfile_path: The filesystem path at which to
                create the output file.
            :return: None.

            """
        self.announce("Writing manual page document to ‘{path}’".format(
                path=outfile_path))

        manpage_writer = document.Writer(manpage, outfile_path)
        manpage_writer.write()

    def run(self):
        """ Execute this command. """
        for maker in self.manpage_makers.values():
            manpage = self.build_manpage(maker)
            self.write_manpage(manpage, maker.output_path)


class DocumentBuilder:
    """ Builder for one manual page document in a distribution.

        Data attributes:

        * `maker`: The `document.ManPageMaker` to use for making the
          document.

        * `distribution`: The `distutils.dist.Distribution` to
          interrogate for the Python distribution fields.

        """

    def __init__(self, maker, distribution):
        self.maker = maker
        self.distribution = distribution

    def make_source_field(self):
        """ Make the “source” field value based on the distribution.

            :return: The text value for the “source” field in a manual
                page header.

            """
        text = "{name} {version}".format(
                name=self.distribution.get_name(),
                version=self.distribution.get_version())
        return text

    def insert_distribution_section(self, manpage):
        """ Insert the section into `manpage` for the distribution.

            :param manpage: The `document.Document` instance to modify.
            :return: None.

            """
        section_index = list(
                manpage.content_sections.keys()
                ).index("SEE ALSO")
        section = self.maker.make_distribution_section(self.distribution)
        manpage.insert_section(section_index, section)

    def build(self):
        """ Build the manual page document.

            :return: The `document.Document` instance.

            """
        metadata = self.maker.metadata
        if metadata.source is None:
            metadata = metadata._replace(source=self.make_source_field())
        self.maker.metadata = metadata

        manpage = self.maker.make_manpage()
        self.insert_distribution_section(manpage)

        return manpage


def assemble_maker(
        maker_class, name, whatis,
        manual=None, section=None, source=None,
        parser=None):
    """ Assemble manual document maker from attributes.

        :param maker_class: The subclass of `ManPageMaker` of which to
            create an instance.
        :param name: The name of the document.
        :param whatis: The succinct one-line description of the document.
        :param manual: The title of the manual to which the document
            belongs.
        :param section: The section code to which the document belongs.
        :param source: The project that includes of the item documented
            in the document.
        :param parser: The `argparse.ArgumentParser` instance from
            which to derive help for the command.

        """
    metadata = document.MetaData(name, whatis, manual, section, source)
    maker = maker_class(metadata)
    if parser is not None:
        maker.set_parser(parser)

    return maker


# This is free software: you may copy, modify, and/or distribute this work
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; version 3 of that license or any later version.
#
# No warranty expressed or implied. See the file ‘LICENSE.GPL-3’ for details,
# or view it online at <URL:https://www.gnu.org/licenses/gpl-3.0.html>.


# Local variables:
# coding: utf-8
# mode: python
# End:
# vim: fileencoding=utf-8 filetype=python :
